package com.duzhuo.springsecurity.handler;

import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.duzhuo.springsecurity.config.TokenManager;
import com.duzhuo.springsecurity.entity.PhoneCodeAuthentication;
import com.duzhuo.springsecurity.utils.*;
import com.duzhuo.springsecurity.vo.LoginVo;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.server.Session;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


/**
 * 认证成功|失败过滤器
 *
 * @author 15714
 */
//@Component
public class TokenLoginFilter extends AbstractAuthenticationProcessingFilter {
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    private TokenManager tokenManager;
    private RedisTemplate redisTemplate;


    public TokenLoginFilter(AuthenticationManager authenticationManager, RedisTemplate redisTemplate) {
        super(new AntPathRequestMatcher("/login", "POST"));
        this.redisTemplate = redisTemplate;
        this.setAuthenticationManager(authenticationManager);
//        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/mylogin", "POST"));
    }

    /**
     * //1 获取表单提交用户名和密码给springsecurity管理
     * 下一步会调用UserDetailsService查询数据库->认证
     *
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            ServletInputStream inputStream = request.getInputStream();
            LoginVo loginVo = JSONObject.<LoginVo>parseObject(IoUtil.readBytes(inputStream), LoginVo.class);
            switch (loginVo.getType()) {
                case "userName_Password":
                    //获取提交数据,封装到User类中
                    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
                            = new UsernamePasswordAuthenticationToken(loginVo.getUserName(), loginVo.getPassword(), new ArrayList<>());
                    return this.getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
                case "phoneVerification":
                    PhoneCodeAuthentication phoneCodeAuthentication = new PhoneCodeAuthentication(loginVo.getPhone(), loginVo.getCode(), new ArrayList<>());
                    return this.getAuthenticationManager().authenticate(phoneCodeAuthentication);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 2 认证成功调用的方法->发放token
     * 返回token 把用户名密码放入redis
     *
     * @param authResult 可以获得UserDetailsService返回的实现->UserDetails接口的类 包含用户信息
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response, FilterChain chain, Authentication authResult) {
/*        //认证成功，得到认证成功之后用户信息
        SecurityUser user = (SecurityUser) authResult.getPrincipal();
        //获取用户名
        String username = user.getUsername();

        // 获取权限信息List
        List<String> permissionValueList = user.getPermissionValueList();
        //权限封装到JWT的Map中
        HashMap<String, Object> hashMap = new HashMap<>(16);
        hashMap.put(TokenManager.ROLE_CLAIMS, permissionValueList);
        //根据用户名生成token


        String token = tokenManager.createToken(username, hashMap);


        //TODO 吧token放入reids
        //把用户名称和用户权限列表放到redis
        redisTemplate.opsForValue().set(username, user.getPermissionValueList());
        //返回token
        response.setHeader(TokenManager.TOKEN_HEADER,TokenManager.TOKEN_PREFIX+token);
        ResponseUtil.out(response, R.ok().data(TokenManager.TOKEN_HEADER, TokenManager.TOKEN_PREFIX + token));*/

        SecurityContextHolder.getContext().setAuthentication(authResult);
        ResponseUtil.out(response, R.ok().data(TokenManager.TOKEN_HEADER, TokenManager.TOKEN_PREFIX + "token" +authResult.toString()));
    }

    //3 认证失败调用的方法
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
            throws IOException, ServletException {
        response.setContentType("text/html;charset=UTF-8");
        ResponseUtil.out(response, R.error());
    }
}
